package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.constant.YeePayConstant;
import cn.huiyunche.base.service.enums.AvailableEnum;
import cn.huiyunche.base.service.framework.utils.HYCUtils;
import cn.huiyunche.base.service.interfaces.CAccntBillService;
import cn.huiyunche.base.service.interfaces.YeepayWebPayService;
import cn.huiyunche.base.service.mappers.CYeepayWebpayLogMapper;
import cn.huiyunche.base.service.mappers.CYeepayWebpayNofityMapper;
import cn.huiyunche.base.service.model.CBill;
import cn.huiyunche.base.service.model.CYeepayWebpayLog;
import cn.huiyunche.base.service.model.CYeepayWebpayLogExample;
import cn.huiyunche.base.service.model.CYeepayWebpayNofity;
import cn.huiyunche.base.service.utils.DateUtils;
import cn.huiyunche.base.service.vo.Result;
import cn.huiyunche.base.service.vo.YeepayWebNotifyVo;
import cn.huiyunche.base.service.vo.YeepayWebPayLogVo;
import com.yeepay.DigestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;

@Service
public class YeepayWebPayServiceImpl implements YeepayWebPayService {

    /**
     * 业务类型
     */
    private static final String p0_Cmd = "Buy";
    /**
     * 交易币种
     */
    private static final String p4_Cur = "CNY";

    @Autowired
    private CAccntBillService cAccntBillService = null;

    @Autowired
    private CYeepayWebpayLogMapper cYeepayWebpayLogMapper = null;

    @Autowired
    private CYeepayWebpayNofityMapper cYeepayWebpayNofityMapper = null;

    @Override
    public Result<Object> init(Long billId, String p8_Url) throws UnsupportedEncodingException {
        Result<Object> r = new Result<>(true);
        Map<String, String> map = new HashMap<>();
        String p1_MerId = HYCUtils.getConstantPropertiesLoader().getProperty(YeePayConstant.YEEPAY_WEBPAY_GROUPID);
        String p2_Order = "hyc_" + UUID.randomUUID().toString().replaceAll("-", "");
        map.put("p0_Cmd", p0_Cmd);
        map.put("p1_MerId", p1_MerId);
        map.put("p2_Order", p2_Order);
        // 获取订单数据
        BigDecimal bd = this.cAccntBillService.getSettlementAmount(billId);
        CBill cb = this.cAccntBillService.selectByPrimaryKey(billId);
        map.put("p3_Amt", bd.doubleValue() + "");
        map.put("p4_Cur", p4_Cur);
        map.put("p8_Url", p8_Url);
        String p5_Pid = "支付【慧运车】" + DateUtils.getStringFromDate(cb.getEndDate(), "MM") + "月份运费";
        map.put("p5_Pid", URLEncoder.encode(p5_Pid, "GBK"));
        map.put("p5_PidUtf8", p5_Pid);
        map.put("hmac", this.getHmac(map, p5_Pid));
        r.setData(map);

        return r;
    }

    @Override
    public Result<Object> addLog(YeepayWebPayLogVo ywplv, Long billId) throws UnsupportedEncodingException {
        Result<Object> r = new Result<>(true);
        // 保存日志
        this.insertYeepayWebPayLog(ywplv, billId);
        return r;
    }

    @Override
    public Result<Object> notify(YeepayWebNotifyVo ywnv) throws UnsupportedEncodingException {
        Result<Object> r = new Result<>(false);
        String[] webpaySignArray = this.getWebpaySignArray(ywnv);
        Boolean hmacIsCorrect = this.verifyCallbackHmac(webpaySignArray, ywnv.getHmac());
        Boolean hmacsafeIsCorrect = this.verifyCallbackHmacSafe(webpaySignArray, ywnv.getHmac_safe());
        if (hmacIsCorrect && hmacsafeIsCorrect) {
            String r6_Order = ywnv.getR6_Order();
            // 是否已经回调，（防止页面和服务器回调两次导致数据错误）
            Boolean isNotify = this.isNotify(r6_Order);
            if (isNotify) {
                r.setSuccess(true);
                return r;
            }
            // 业务处理
            CYeepayWebpayLog cywl = this.getLogByR6OrderId(r6_Order);
            if (null == cywl) {
                r.setMessage("找不到支付订单流水");
                return r;
            }
            // 账单处理
            Result<String> billResult = this.cAccntBillService.payBillFinish(cywl.getBillId());
            if (!billResult.isSuccess()) {
                r.setMessage(billResult.getMessage());
                return r;
            }
            // 添加修改日志
            this.modifyYeepayWebpayLog(r6_Order);
            this.addYeepayWenPayNotify(ywnv);
            r.setSuccess(true);
        } else {
            r.setMessage("易宝支付回调签名校验错误");
        }
        return r;
    }

    /**
     * 获取hmac
     *
     * @param map    数据集合
     * @param p5_Pid 密钥
     * @return
     */
    private String getHmac(Map<String, String> map, String p5_Pid) {
        // 商户号
        String[] strArr = new String[]{map.get("p0_Cmd"), map.get("p1_MerId"), map.get("p2_Order"), map.get("p3_Amt"), map.get("p4_Cur"), p5_Pid, "", "", map.get("p8_Url"), "", "", "", ""};
        // 密钥
        return DigestUtil.getHmac(strArr, HYCUtils.getConstantPropertiesLoader().getProperty(YeePayConstant.YEEPAY_WEBPAY_GROUPCA));
    }

    /**
     * 添加网银支付日志
     *
     * @param ywplv
     * @param billId
     */
    private void insertYeepayWebPayLog(YeepayWebPayLogVo ywplv, Long billId) {
        CYeepayWebpayLog cywl = new CYeepayWebpayLog();
        cywl.setBillId(billId);
        cywl.setCreateTime(new Date());
        cywl.setHmac(ywplv.getHmac());
        cywl.setP0Cmd(ywplv.getP0_Cmd());
        cywl.setP1Merid(ywplv.getP1_MerId());
        cywl.setP2Order(ywplv.getP2_Order());
        cywl.setP3Amt(ywplv.getP3_Amt());
        cywl.setP4Cur(ywplv.getP4_Cur());
        cywl.setP5Pid(ywplv.getP5_Pid());
        cywl.setP8Url(ywplv.getP8_Url());
        this.cYeepayWebpayLogMapper.insert(cywl);
    }

    /**
     * 获取签名数组
     *
     * @param ywnv
     * @return
     */
    private String[] getWebpaySignArray(YeepayWebNotifyVo ywnv) {
        String[] strArr = {ywnv.getP1_MerId(), ywnv.getR0_Cmd(), ywnv.getR1_Code(), ywnv.getR2_TrxId(), ywnv.getR3_Amt(), ywnv.getR4_Cur(), ywnv.getR5_Pid(), ywnv.getR6_Order(), ywnv.getR7_Uid(), ywnv.getR8_MP(), ywnv.getR9_BType()};
        return strArr;
    }

    /**
     * 验证回调参数是否有效
     *
     * @param stringValue
     * @param hmacFromYeepay
     * @return
     * @throws UnsupportedEncodingException
     */
    private Boolean verifyCallbackHmac(String[] stringValue, String hmacFromYeepay) throws UnsupportedEncodingException {
        String keyValue = HYCUtils.getConstantPropertiesLoader().getProperty(YeePayConstant.YEEPAY_WEBPAY_GROUPCA);
        String localHmac = DigestUtil.getHmac(stringValue, keyValue);
        return (localHmac.equals(hmacFromYeepay));
    }

    /**
     * 验证回调安全签名数据是否有效
     *
     * @param stringValue
     * @param hmac_safeFromYeepay
     * @return
     */
    private Boolean verifyCallbackHmacSafe(String[] stringValue, String hmac_safeFromYeepay) {
        String keyValue = HYCUtils.getConstantPropertiesLoader().getProperty(YeePayConstant.YEEPAY_WEBPAY_GROUPCA);
        StringBuffer sourceData = new StringBuffer();
        for (int i = 0; i < stringValue.length; i++) {
            if (!"".equals(stringValue[i])) {
                sourceData.append(stringValue[i] + "#");
            }
        }
        sourceData = sourceData.deleteCharAt(sourceData.length() - 1);
        String localHmac_safe = DigestUtil.hmacSign(sourceData.toString(), keyValue);
        StringBuffer hmacSource = new StringBuffer();
        for (int i = 0; i < stringValue.length; i++) {
            hmacSource.append(stringValue[i]);
        }
        return (localHmac_safe.equals(hmac_safeFromYeepay));
    }

    /**
     * 获取订单日志信息
     *
     * @param r6_OrderId
     * @return
     */
    private CYeepayWebpayLog getLogByR6OrderId(String r6_OrderId) {
        CYeepayWebpayLogExample cywle = new CYeepayWebpayLogExample();
        cywle.createCriteria().andP2OrderEqualTo(r6_OrderId);
        List<CYeepayWebpayLog> list = this.cYeepayWebpayLogMapper.selectByExample(cywle);
        return list.size() > 0 ? list.get(0) : null;
    }

    /**
     * 检测是否已经回调
     *
     * @param r6_Order
     * @return
     */
    private Boolean isNotify(String r6_Order) {
        CYeepayWebpayLogExample cywle = new CYeepayWebpayLogExample();
        cywle.createCriteria().andP2OrderEqualTo(r6_Order).andNotifyStatusEqualTo(AvailableEnum.T.getValue());
        List<CYeepayWebpayLog> list = this.cYeepayWebpayLogMapper.selectByExample(cywle);
        return list.size() > 0;
    }

    /**
     * 更新网银支付日志
     *
     * @param r6_Order
     */
    private void modifyYeepayWebpayLog(String r6_Order) {
        CYeepayWebpayLogExample cywle = new CYeepayWebpayLogExample();
        cywle.createCriteria().andP2OrderEqualTo(r6_Order);
        List<CYeepayWebpayLog> list = this.cYeepayWebpayLogMapper.selectByExample(cywle);
        CYeepayWebpayLog cywl = list.size() > 0 ? list.get(0) : null;
        if (null != cywl) {
            cywl.setNotifyStatus(AvailableEnum.T.getValue());
            cywl.setNotifyTime(new Date());
            this.cYeepayWebpayLogMapper.updateByPrimaryKey(cywl);
        }
    }

    /**
     * 添加回调日志
     *
     * @param ywnv
     * @throws UnsupportedEncodingException
     */
    private void addYeepayWenPayNotify(YeepayWebNotifyVo ywnv) throws UnsupportedEncodingException {
        CYeepayWebpayNofity cywn = new CYeepayWebpayNofity();
        cywn.setHmac(ywnv.getHmac());
        cywn.setHmacSafe(ywnv.getHmac_safe());
        cywn.setP1Merid(ywnv.getP1_MerId());
        cywn.setR0Cmd(ywnv.getR0_Cmd());
        cywn.setR1Code(ywnv.getR1_Code());
        cywn.setR2Trxid(ywnv.getR2_TrxId());
        cywn.setR3Amt(ywnv.getR3_Amt());
        cywn.setR4Cur(ywnv.getR4_Cur());
        cywn.setR5Pid(URLDecoder.decode(ywnv.getR5_Pid(), "GBK"));
        cywn.setR6Order(ywnv.getR6_Order());
        cywn.setR7Uid(ywnv.getR7_Uid());
        cywn.setR8Mp(ywnv.getR8_MP());
        cywn.setR9Btype(ywnv.getR9_BType());
        cywn.setRbBankid(ywnv.getRb_BankId());
        cywn.setRoBankorderid(ywnv.getRo_BankOrderId());
        cywn.setRpPaydate(ywnv.getRp_PayDate());
        cywn.setRqCardno(ywnv.getRq_CardNo());
        cywn.setRqSourcefe(ywnv.getRq_SourceFee());
        cywn.setRqTargetfee(ywnv.getRq_TargetFee());
        cywn.setRuTrxtime(ywnv.getRu_Trxtime());
        this.cYeepayWebpayNofityMapper.insert(cywn);
    }

}
